var mysql = require('mysql');
var path = require('path');
var express = require('express');
var uuid = require('node-uuid');
var bodyParser = require('body-parser');
var ws = require('ws');
var minimist = require('minimist');
var url = require('url');
var kurento = require('kurento-client');
var fs    = require('fs');
var https = require('https');
var http = require('http');
var Mqtt = require('mqtt');
var format = require('string-format');
format.extend(String.prototype);
var AliyunCore = require('@alicloud/pop-core');
var request = require('request');
var urlencode = require('urlencode');

function THHComm() {
    this.cb = function (callback, p0, p1, p2) {
        try {
            if (callback) {
                callback(p0, p1, p2);
            }
        } catch (e) {
            console.log(e)
        }
    };
    this.isNull = function (obj) {
        var flag = (!obj) || (obj==null);
        return flag;
    };
    this.newId = function (splitStr) {
        var sp = splitStr && splitStr != null ? splitStr : "";
        return [(new Date()).getTime().toString(), parseInt(1000 * Math.random()).toString()].join(splitStr);
    };
    this.getDictItems = function (dict) {
        var res = [];
        for (var p in dict) {
            res.push(dict[p]);
        }
        return res;
    };
    this.getDictValue = function (dict, key, defaultValue) {
        var res = (dict && dict != null && dict[key]) ? dict[key] : defaultValue;
        return res;
    };
    this.extend = function ( a , b) {
        try{
            if( a==null || !a){
                a = {};
            }
            if( b && b!=null){
                for( p in b ){
                    a[p] = b[p];
                }
            }
        }
        catch (e) {
            console.log(e);
        }
        return a;
    };
    this.makeDir = function (dirpath) {
        if (!fs.existsSync(dirpath)) {
            var pathtmp;
            dirpath.split("/").forEach(function(dirname) {
                if (pathtmp) {
                    pathtmp = path.join(pathtmp, dirname);
                }
                else {
    　　　　　　　　　 //如果在linux系统中，第一个dirname的值为空，所以赋值为"/"
                    if(dirname){
                        pathtmp = dirname;
                    }else{
                        pathtmp = "/";
                    }
                }
                if (!fs.existsSync(pathtmp)) {
                    if (!fs.mkdirSync(pathtmp)) {
                        return false;
                    }
                }
            });
        }else{
            return true;
        }
        return true;
    }
}

var comm = new THHComm();

function THHDB() {
    this.apps = {};
    this.pools = {};
    this.getSql = function (appId, key) {
        var sql = "";
        var me = this;
        try {
            if (me.apps[appId]) {
                var sqlPath = ([me.apps[appId].sqlPath, key].join("/")).replace("//", "/");
                if (sqlPath.toLowerCase().indexOf(".txt") <= 0) {
                    sqlPath = sqlPath + ".txt";
                }
                try {
                    sql = fs.readFileSync(sqlPath, 'utf-8');
                } catch (er) {
                    sql = "";
                }
            }
        } catch (e) {
            console.log(e)
        }
        return sql;
    };
    this.query = function (appId, sql, ps, onQuery) {
        var me = this;
        try {
            var dbInfo = null;
            if (me.apps[appId]) {
                dbInfo = me.apps[appId];
                if (!dbInfo.pool) {
                    dbInfo.pool = mysql.createPool({
                        host: dbInfo.host,
                        port: dbInfo.port,
                        user: dbInfo.uid,
                        password: dbInfo.pwd,
                        database: dbInfo.db,
                        connectionLimit: 100
                    });
                }
                dbInfo.pool.getConnection(function (err, conn) {
                    try {
                        conn.query(sql, ps, function (errQuery, results, fields) {
                            conn.release();
                            if (errQuery) {
                                comm.cb(onQuery, {error: errQuery});
                                console.log(errQuery, sql, ps);
                            } else {
                                var res = JSON.parse(JSON.stringify(results));
                                comm.cb(onQuery, null, res);
                            }
                        })
                    } catch (err) {
                        console.log(err);
                    }
                });
            } else {
                comm.cb(onQuery, {error: "appId is error."});
            }
        } catch (e) {
            console.log(e)
        }
    };
    this.queryByFn = function (appId, sqlKeyFn, ps, onQuery) {
        var me = this;
        try {
            var sql = me.getSql(appId, sqlKeyFn);
            if (sql == "") {
                comm.cb(onQuery, {error: "key is error."});
            } else {
                me.query(appId, sql, ps, onQuery);
            }
        } catch (e) {
            console.log(e)
        }
    };
}

function THHMQ() {
    var me = this;
    this.config = {
        server: 'ssl://gmggf8g.mqtt.iot.bj.baidubce.com:1884',
        options: {
            username: 'gmggf8g/peer',
            password: 'a52bwKg22dCAuQzB',
            clientId: 'busi_s_' + (new Date()).getTime().toString()
        },
        autoTopics: []
    };
    this.client = null;
    this.events = {
        onConnect: function () {
        },
        onMsg: function (topic, msg) {
        }
    };
    this.getClientId = function () {
        var res = (me.config.clientId &&
            me.config.clientId != null &&
            me.config.clientId != "") ? me.config.clientId : comm.newId('cId_');
        return res;
    }
    this.connect = function () {
        try {
            me.disconnect();
            me.config.options.clientId = me.getClientId();
            var client = Mqtt.connect(me.config.server, me.config.options);
            client.on('error', function (error) {
                console.error(error);
                client = null;
            });
            client.on('connect', function () {
                try {
                    console.log('Connected. Client id is: ' + me.config.options.clientId);
                    if (me.config.autoTopics) {
                        try {
                            me.config.autoTopics.forEach(function (topic) {
                                client.subscribe(topic);
                            })
                        } catch (er) {
                            console.log(er);
                        }
                    }
                    comm.cb(me.events.onConnect);
                } catch (er) {
                    console.log(er)
                }
            });
            client.on('disconnect', function () {
                try {
                    console.log('disconnect. Client id is: ' + me.config.options.clientId);
                } catch (er) {
                    console.log(er)
                }
            });
            client.on('message', function (topic, data) {
                try {
                    var msgInfo = JSON.parse(data);
                    me.events.onMsg(topic, msgInfo);
                } catch (er) {
                    console.log(er)
                }
            });
            me.client = client;
        } catch (e) {
            console.log(e)
        }
    };
    this.disconnect = function () {
        try {
            if (me.client && me.client != null && me.client.isConnected()) {
                me.client.disconnect();
                me.client = null;
            }
        } catch (e) {
            console.log(e)
        }
    };
    this.sendMsg = function (topic, msgInfo) {
        try {
            me.client.publish(topic, JSON.stringify(msgInfo));
        } catch (e) {
            console.log(e)
        }
    };
}

function THHKms() {
    var me = this;
    this.config = {
        kmsUrl: "wss://wss.hhdata.cn:8433/kurento"
        //kmsUrl:"wss://wss.hhdata.cn:8433/kurento"
    };
    this.objs = {
        kmsClient: null
    };
    this.dataItems = {};
    this.getClient = function (callback) {
        try {
            if (me.objs.kmsClient && me.objs.kmsClient != null) {
                try {
                    comm.cb(callback, me.objs.kmsClient);
                    /*
                    me.objs.kmsClient.getServerManager(function (errSvr , svr) {
                        if( svr ){
                            comm.cb(callback, me.objs.kmsClient);
                        }
                        else{
                            newClient();
                        }
                    })
                    */
                } catch (err) {
                    newClient();
                }
            } else {
                newClient();
            }
            var newClient = function () {
                kurento(me.config.kmsUrl, function (err, client) {
                    client.getServerManager(function (erSvr, svr) {
                        client.serverManager = svr;
                        me.updateDataItems(function () {
                            me.objs.kmsClient = client;
                            comm.cb(callback, client);
                            var loopHandler = function () {
                                setTimeout(function () {
                                    me.updateDataItems(function () {
                                        loopHandler();
                                    })
                                }, 10 * 1000 * 60)

                            };
                            loopHandler();
                        })
                    });
                });
            }
        } catch (e) {
            console.log(e)
        }
    };
    this.freeObj = function (objId, onFree) {
        try {
            me.getClient(function (client) {
                if (me.dataItems[objId]) {
                    var kmsId = me.dataItems[objId].kmsId;
                    client.getMediaobjectById(kmsId, function (erFind, kmsObj) {
                        if (kmsObj) {
                            kmsObj.release(function () {
                                comm.cb(onFree);
                            })
                        } else {
                            comm.cb(onFree);
                        }
                    })
                } else {
                    comm.cb(onFree);
                }
            })
        } catch (e) {
            console.log(e)
        }
    };
    this.setDataItem = function (key, info, onSet) {
        try {
            me.getClient(function (client) {
                client.serverManager.addTag(key, JSON.parse(info), function (erTag) {
                    if (!erTag) {
                        me.dataItems[key] = dataItem;
                    }
                    comm.cb(onSet, erTag);
                })
            })
        } catch (e) {
            console.log(e)
        }
    };
    this.getKmsObj = function (objId, onGet) {
        try {
            var res = null
            me.getClient(function (client) {
                if (me.dataItems[objId]) {
                    var kmsId = me.dataItems[objId].kmsId;
                    client.getMediaobjectById(kmsId, function (erFind, kmsObj) {
                        if (kmsObj) {
                            res = {
                                dateItem: me.dataItems[objId],
                                kmsObj: kmsObj
                            };
                        }
                        comm.cb(onGet, res);
                    })
                } else {
                    onGet();
                }
            })
        } catch (e) {
            console.log(e)
        }
    };
    this.updateDataItems = function (onUpdate) {
        try {
            var dataItems = {};
            me.objs.kmsClient.serverManager.getTags(function (erTags, tags) {
                tags.forEach(function (tag) {
                    var k = tag.key;
                    var v = tag.v;
                    var val = {};
                    var isJson = (v.indexOf("{") > 0 && v.indexOf("}") > 0) || (v.indexOf("[") > 0 && v.indexOf("]") > 0);
                    if (isJson) {
                        try {
                            val = JSON.parse(v);
                        } catch (erJson) {
                            val = v;
                        }
                    } else {
                        val = v.toString();
                    }
                    ;
                    dataItems[k] = val;
                });
                me.dataItems = dataItems;
                onUpdate();
            })
        } catch (e) {
            console.log(e)
        }
    };
    this.newChannel = function (channelId, channelInfo, onCreate) {
        try {
            me.getClient(function (client) {
                client.create("MediaPipeline", function (erNew, np) {
                    var info = {
                        objId: channelId,
                        kmsId: np.id,
                        tag: channelInfo
                    };
                    me.setDataItem(channelId, info, function () {
                        comm.cb(onCreate, info, np);
                    })
                })
            })
        } catch (e) {
            console.log(e);
        }
    };
    this.newPlayer = function (pipe, playerId, playerInfo, url, onCreate) {
        try {
            me.getClient(function (client) {
                pipe.create("PlayerEndppoint", {uri: url}, function (erNew, np) {
                    var info = {
                        objId: playerId,
                        kmsId: np.id,
                        tag: playerInfo
                    };
                    me.setDataItem(playerId, info, function () {
                        comm.cb(onCreate, info, np);
                    })
                })
            })
        } catch (e) {
            console.log(e);
        }
    };
    this.newWebRtcEnd = function (pipe, endId, endInfo, onCreate) {
        try {
            me.getClient(function (client) {
                pipe.create("WebRtcEndpoint", function (erNew, end) {
                    var info = {
                        objId: endId,
                        kmsId: end.id,
                        tag: endInfo
                    };
                    me.setDataItem(endId, info, function () {
                        comm.cb(onCreate, info, end);
                    })
                })
            })
        } catch (e) {
            console.log(e);
        }
    };
}

function THHAppRoom() {
    var me = this;
    this.config = {
        apps: {},
        kmsUrl: "wss://wss.hhdata.cn:8433/kurento"
    };
    this.datas = {
        kmsClient: null
    };
    this.getClient = function (callback) {
        try {
            var newClient = function () {
                try {
                    kurento(me.config.kmsUrl, function (err, client) {
                        client.getServerManager(function (erFind, svr) {
                            client.serverManager = svr;
                            me.datas.kmsClient = client;
                            comm.cb(callback, me.datas.kmsClient);
                        })
                    });
                } catch (err) {
                    newClient();
                }
            };
            if (me.datas.kmsClient && me.datas.kmsClient != null) {
                try {
                    me.datas.kmsClient.getServerManager(function (erFind, svr) {
                        if (erFind) {
                            newClient();
                        } else {
                            me.datas.kmsClient.serverManager = svr;
                            comm.cb(callback, me.datas.kmsClient);
                        }
                    })
                } catch (err) {
                    newClient();
                }
            } else {
                newClient();
            }
        } catch (e) {
            console.log(e);
        }
    }
    this.getRooms = function (callback) {
        try {
            var res = [];
            me.getClient(function (client) {
                client.serverManager.getPipelines(function (erPs, ps) {
                    var index = 0;
                    var getPipe = function () {
                        if (index < ps.length) {
                            var p = ps[index];
                            p.getName(function (erName, name) {
                                p.getTag('roomInfo', function (erTag, tag) {
                                    if (!erTag) {
                                        res.push({
                                            roomId: name,
                                            kmsId: p.id,
                                            roomInfo: JSON.parse(tag),
                                            pipe: p
                                        });
                                    }
                                    index++;
                                    getPipe();
                                })
                            });

                        } else {
                            comm.cb(callback, res);
                        }
                    };
                    getPipe();
                })
            })
        } catch (e) {
            console.log(e);
        }
    };
    this.getRoomInfo = function (roomId, callback) {
        try {
            var getPipeEnds = function(pipe,onGet){
                pipe.getChildren(function (erChild , items) {
                    var ind =0;
                    var ends = items.filter(function (item) {
                        return item.id.indexOf('Endpoint')>0;
                    });
                    var res =[];
                    var getEnd = function () {
                        if( ind< ends.length){
                            var end = ends[ind];
                            end.getName(function (erName , name) {
                                end.getTag('endInfo', function (erTag , tag) {
                                    if(!erTag){
                                        res.push({
                                            endId: name ,
                                            kmsId: end.id ,
                                            endInfo: JSON.parse(tag) ,
                                            end:end
                                        });
                                    }
                                    ind++;
                                    getEnd();
                                })
                            });
                        }
                        else{
                            onGet(res);
                        }
                    };
                    getEnd();
                });
            };
            me.getClient(function (client) {
                client.serverManager.getPipelines(function (erPs, ps) {
                    var index = 0;
                    var getPipe = function () {
                        if (index < ps.length) {
                            var p = ps[index];
                            p.getName(function (erName, name) {
                                if (name == roomId) {
                                    p.getTag('roomInfo', function (erTag, tag) {
                                        var res = {
                                            roomId: name,
                                            kmsId: p.id,
                                            roomInfo: JSON.parse(tag),
                                            pipe: p
                                        };
                                        getPipeEnds(p, function (ends) {
                                            res.ends = ends;
                                            comm.cb(callback, res);
                                        })
                                    })
                                }
                                else{
                                    index++;
                                    getPipe();
                                }
                            });
                        } else {
                            comm.cb(callback);
                        }
                    };
                    getPipe();
                })
            })
        } catch (e) {
            console.log(e);
        }
    };
    this.getEndStatus = function (roomId, endId, callback) {
        try {
            me.getRoomInfo(function (roomInfo) {
                var ends = roomInfo.ends.filter(function (item) {
                    return item.endId == endId;
                });
                comm.cb(callback , ends.length>0? ends[0]: null);
            })
        } catch (e) {
            console.log(e);
        }
    };
    this.openRoom = function (roomId, roomInfo, callback) {
        try {
            me.getClient(function (client) {
                client.serverManager.getPipelines(function (erPs, ps) {
                    var newPipe = function () {
                        client.create("MediaPipeline", function (erNewP, np) {
                            np.setName(roomId, function (erName) {
                                np.addTag("roomInfo", JSON.stringify(roomInfo), function (erTag) {
                                    var res = {
                                        roomId: roomId,
                                        kmsId: np.id,
                                        pipe: np
                                    };
                                    comm.cb(callback, res);
                                })
                            })
                        })
                    };
                    var index = 0;
                    var getPipe = function () {
                        if (index < ps.length) {
                            var p = ps[index];
                            p.getName(function (erName, name) {
                                if (name == roomId) {
                                    var res = {
                                        roomId: roomId,
                                        kmsId: p.id,
                                        pipe: p
                                    };
                                    comm.cb(callback, res);
                                } else {
                                    index++;
                                    getPipe();
                                }
                            })
                        } else {
                            newPipe();
                        }
                    };
                    getPipe();
                })
            })
        } catch (e) {
            console.log(e);
        }
    };
    this.closeRoom = function (roomId, callback) {
        try {
            me.getRoomInfo(roomId, function (roomInfo) {
                if( roomInfo){
                    var index = 0;
                    var freeEnds = function () {
                        if( index < roomInfo.ends.length){
                            var end = roomInfo.ends[index];
                            end.end.release(function () {
                                index++;
                                freeEnds();
                            })
                        }
                        else{
                            roomInfo.pipe.release(function () {
                                comm.cb(callback);
                            })
                        }
                    };
                    freeEnds();
                }
                else{
                    comm.cb(callback);
                }
            })
        } catch (e) {
            console.log(e);
        }
    };
    this.createEnd = function (roomId, endType, endId, endOptions, endInfo, callback) {
        try {
            me.getRoomInfo(roomId, function (roomData) {
                if( roomData && roomData!=null) {
                    var pipe = roomData.pipe;
                    pipe.getChildren(function (erChild, children) {
                        var index = 0;
                        var getEnd = function () {
                            if (index < children.length) {
                                var end = children[index];
                                end.getName(function (erName, name) {
                                    if (name == endId) {
                                        var res = {status:1, endResult :{
                                            endId: endId,
                                            kmsId: end.id,
                                            end: end
                                        }};
                                        comm.cb(callback, res);
                                    } else {
                                        index++;
                                        getEnd();
                                    }
                                });
                            } else {
                                pipe.create(endType, endOptions, function (erNewEnd, end) {
                                    end.setName(endId, function (erName) {
                                        end.addTag("endInfo", JSON.stringify(endInfo), function (erTag) {
                                            var res = {status:2, endResult :{
                                                endId: endId,
                                                kmsId: end.id,
                                                end: end
                                            }};
                                            comm.cb(callback, res);
                                        })
                                    })
                                })
                            }
                        };
                        getEnd();
                    });
                }
                else{
                    var res = {status:0, endResult: null};
                    comm.cb(callback, res);
                }
            })
        } catch (e) {
            console.log(e);
        }
    };
    this.freeEnd = function (roomId , endId, callback) {
        try {
            me.getEndStatus(roomId, endId , function (end) {
                if( end && end.end){
                    end.end.release(function () {
                        comm.cb(callback);
                    });
                }
            })
        } catch (e) {
            console.log(e);
        }
    };
}

function THHApi() {
    var me = this;
    this.config = {
        port: 20024,
        keyFn: "E:/app/kmsdev/dev/svr/keys/4195813_wss.hhdata.cn.key",
        certFn: "E:/app/kmsdev/dev/svr/keys/4195813_wss.hhdata.cn.pem",
        apiRootPath: "hhapi",
        staticPaths: {
            "/": "e:/app/kmsdev/dev/static"
        }
    };
    this.objs = {
        app: null,
        server: null
    };
    this.routes = {};
    this.start = function (routes, onStart) {
        try {
            me.routes = routes;
            var apiPath = ("/" + [me.config.apiRootPath, ":ac"].join("/")).replace("//", "/");
            var app = express();
            for (sp in me.config.staticPaths) {
                app.use(sp, express.static(me.config.staticPaths[sp]));
            }
            var urlencodedParser = bodyParser.urlencoded({extended: false});
            app.use(urlencodedParser);
            app.use(bodyParser.json());
            var jsonParser = bodyParser.json();
            app.all(apiPath, jsonParser, function (req, res) {
                var ac = req.params.ac;
                res.header("Access-Control-Allow-Origin", "*");
                res.header("Access-Control-Allow-Headers", "content-type");
                res.header("Access-Control-Allow-Methods", "DELETE,PUT,POST,GET,OPTIONS");
                var ps = comm.extend({}, req.query);
                var result = {
                    ac: ac,
                    ps: ps,
                    error: null,
                    data: null
                };
                var handler = function (respResult) {
                    if (me.routes[respResult.ac]) {
                        me.routes[respResult.ac](respResult, req, res);
                    }
                };
                if (req.method == "POST") {
                    if( req.headers["content-type"].indexOf('application/json')>=0 ){
                        ps = comm.extend(ps, req.body);
                        handler(result);
                    }
                    else {
                        req.setEncoding('utf8');
                        req.on('data', function (data) {
                            try {
                                var obj = JSON.parse(data);
                                ps = extend(ps, obj);
                            } catch (ee) {
                                console.log(ee)
                            }
                        });
                        req.on('end', function () {
                            handler(result);
                        });
                    }
                } else if (req.method == "GET") {
                    handler(result);
                }
            });
            var options = {};
            if (me.config.keyFn && me.config.keyFn != null && me.config.keyFn.length > 0) {
                options = {
                    key: fs.readFileSync(me.config.keyFn),
                    cert: fs.readFileSync(me.config.certFn)
                };
            }
            var httpsServer = https.createServer(options, app);
            httpsServer.listen(me.config.port, function (err) {
                if (err) {
                    comm.cb(onStart, {error: err});
                } else {
                    me.objs.app = app;
                    me.objs.server = httpsServer;
                    comm.cb(onStart);
                }
            });
        } catch (e) {
            console.log(e);
        }
    }
}

function THHWx() {
    var me = this;
    this.wxApps = {
        wx29435f02de2545d8: {
            ak: "wx29435f02de2545d8",
            sk: "b0915f992c6661ef0fb5155353788e40",//交换位置
            redirectUrl: "https://wx.hhdata.cn/apps/wss/wxCode.htm",
            users: {},
            desc:"河海协同"
        }
    };
    this.requestUserInfo = function ( reqPs , callback) {
        var res = {
            status:0 ,
            errMsg:"",
            data:null
        };
        var ps ={
            ak:"",
            code :"",
            tag: "",
            openId:"" ,
            accessToken :"",
            accessTime:0,
            refreshToken:"",
            refreshTime:0,
            userInfo:{},
            loginUrl:""
        };
        try {
            ps = comm.extend(ps, reqPs);
            if( me.wxApps[ps.ak]){
                var wxApp = me.wxApps[ps.ak];
                var sk = wxApp.sk;
                var now = (new Date()).getTime();
                var redirectWxApi= function () {
                    var reUrl = urlencode(wxApp.redirectUrl);
                    reUrl += reUrl.indexOf('?')>0?"&":"?";
                    reUrl += "tag="+ps.tag;
                    var ak = wxApp.ak;
                    var state = ps.tag;
                    var redirectUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + ak + "&redirect_uri=" + reUrl + "&response_type=code&scope=snsapi_userinfo&state=" + state + "#wechat_redirect";
                    res.status =9 ;
                    res.data = redirectUrl;
                    comm.cb(callback , res);
                }
                var getAccessTokenByCode= function (onGetAccessToken) {
                    var ak = ps.ak;
                    var code = ps.code;
                    var url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + ak + "&secret=" + sk + "&code=" + code + "&grant_type=authorization_code";
                    request(url, function (error, response, body) {
                        if (response && response.statusCode == 200) {
                            var accessTokenResp = JSON.parse(body);
                            var accessData = {
                                openId:accessTokenResp.openid ,
                                accessToken :accessTokenResp.access_token,
                                accessTime:now,
                                refreshToken:accessTokenResp.refresh_token,
                                refreshTime:now
                            };
                            onGetAccessToken(accessData);
                        } else {
                            onGetAccessToken(null);
                        }
                    });
                }
                var refreshAccessToken= function (onRefreshAccessToken) {
                    var ak = ps.ak;
                    var reToken = ps.RefreshToken;
                    var url = "https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=" + ak + "&grant_type=refresh_token&refresh_token=" + reToken;
                    request(url, function (error, response, body) {
                        if (response && response.statusCode == 200) {
                            var accessTokenResp = JSON.parse(body);
                            var accessData = {
                                openId:accessTokenResp.openid ,
                                accessToken :accessTokenResp.access_token,
                                accessTime:ps.accessTime,
                                refreshToken:accessTokenResp.refresh_token,
                                refreshTime:now
                            };
                            onRefreshAccessToken(accessData);
                        } else {
                            onGetAccessToken(null);
                        }
                    });

                }
                var getUserInfoByAccessToken= function (token , onGetUserInfo) {
                    var accessToken = token.accessToken;
                    var openId = token.openId;
                    var urlUser = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId + "&lang=zh_CN";
                    request(urlUser, function (err, responseUser, bodyUser) {
                        if (responseUser && responseUser.statusCode == 200) {
                            var userInfo = JSON.parse(bodyUser);
                            onGetUserInfo(userInfo);

                        } else {
                            onGetUserInfo(null);
                        }
                    });
                }
                if( ps.code==""){
                    if( ps.accessToken=="" || !(wxApp.users[ps.accessToken])){
                        redirectWxApi();
                    }
                    else {
                        var refreshTimeout = now - ps.refreshTime> 28* 24 * 3600 * 1000;
                        if( refreshTimeout){
                            redirectWxApi();
                        }
                        else{
                            var accessTimeout = now - ps.accessTime > 7000*1000;
                            if( accessTimeout){
                                delete wxApp.users[ps.accessToken];
                                refreshAccessToken(function (resToken) {
                                    if( resToken==null){
                                        res.status = -4 ;
                                        res.errMsg ="refresh access token faild.";
                                        comm.cb(callback , res);
                                    }
                                    else {
                                        resToken.accessTime = ps.accessTime;
                                        getUserInfoByAccessToken(resToken, function (resUserInfo) {
                                            me.users[resToken.accessToken] = resToken;
                                            resToken.userInfo = resUserInfo;
                                            res.status = 1;
                                            res.data = resToken;
                                            comm.cb(callback, res);
                                        })
                                    }
                                })
                            }
                            else{
                                res.status = 1;
                                res.data = wxApp.users[ps.accessToken];
                                comm.cb( callback , res);
                            }
                        }
                    }
                }
                else{
                    getAccessTokenByCode( function (resToken) {
                        if(resToken==null){
                            res.status = -2;
                            res.errMsg = "get access token faild";
                            comm.cb(callback, res);
                        }
                        else {
                            getUserInfoByAccessToken(resToken, function (resUserInfo) {
                                if( resUserInfo==null){
                                    res.status = -3;
                                    res.errMsg = "get user info faild.";
                                    comm.cb(callback, res);

                                }
                                else {
                                    wxApp.users[resToken.accessToken] = resToken;
                                    resToken.userInfo = resUserInfo;
                                    res.status = 1;
                                    res.data = resToken;
                                    comm.cb(callback, res);
                                }
                            })
                        }
                    })
                }
            }
            else{
                res.status =-1;
                res.errMsg = "appId is error.";
                comm.cb(callback , res);
            }
        } catch (e) {
            console.log(e);
        }
    };
}

function THHWxLogin() {
    var me = this;
    this.urls ={
        redirectUrl:"https://open.weixin.qq.com/connect/oauth2/authorize?appid=[ak]&redirect_uri=[reUrl]&response_type=code&scope=snsapi_userinfo&state=[state]#wechat_redirect" ,
        getAccessToken:"https://api.weixin.qq.com/sns/oauth2/access_token?appid=[ak]&secret=[sk]&code=[code]&grant_type=authorization_code",
        getUserInfo:"https://api.weixin.qq.com/sns/userinfo?access_token=[accessToken]&openid=[openId]&lang=zh_CN" ,
        refreshToken:"https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=[ak]&grant_type=refresh_token&refresh_token=[refreshToken]"
    };
    this.wxApps ={
        heHaiXieTong:{
            desc:"河海协同",
            ak: "wx29435f02de2545d8",
            sk: "b0915f992c6661ef0fb5155353788e40",//交换位置 b在前正确
            redirectUrl: "https://wx.hhdata.cn/apps/wss/wxBridge.htm",
        }
    };
    this.getRedirectUrl = function (wxAppId , state) {
        var res ="";
        if( me.wxApps[wxAppId]){
            var reUrl = urlencode(me.wxApps[wxAppId].redirectUrl);
            var urlFormat = me.urls.redirectUrl;
            res = urlFormat.replace('[ak]', me.wxApps[wxAppId].ak );
            res = res.replace('[state]', state );
            res = res.replace('[reUrl]', reUrl );
        }
        return res;
    };
    this.getAccessTokenByCode = function (wxAppId , code , onGet) {
        if( me.wxApps[wxAppId]){
            var data = JSON.parse(JSON.stringify(me.wxApps[wxAppId]));
            data.code = code;
            var urlFormt = me.urls.getAccessToken;
            var url = urlFormt;
            for( p in data){
                var k = "["+p+"]";
                var v = data[p];
                url = url.replace(k,v);
            }
            var res={
                status:-2,
                accessToken:null
            }
            request(url, function (err, responseUser, bodyUser) {
                if (responseUser && responseUser.statusCode == 200) {
                    var accessToken = JSON.parse(bodyUser);
                    if( accessToken.openid && accessToken.openid!=null && accessToken.openid.length>0){
                        res.status =1 ;
                        res.accessToken = accessToken;
                    }
                }
                onGet(res.accessToken);
            });
        }
    };
    this.getAccessTokenByRefresh = function (wxAppId , refreshToken  , onGet) {
        if( me.wxApps[wxAppId]){
            var data = JSON.parse(JSON.stringify(me.wxApps[wxAppId]));
            data.refreshToken = refreshToken;
            var urlFormt = me.urls.refreshToken;
            var url = urlFormt;
            for( p in data){
                var k = "["+p+"]";
                var v = data[p];
                url = url.replace(k,v);
            }
            var res={
                status:-2,
                accessToken:null
            }
            request(url, function (err, responseUser, bodyUser) {
                if (responseUser && responseUser.statusCode == 200) {
                    var accessToken = JSON.parse(bodyUser);
                    if( accessToken.openid && accessToken.openid!=null && accessToken.openid.length>0){
                        res.status =1 ;
                        res.accessToken = accessToken;
                    }
                }
                onGet(res.accessToken);
            });
        }
    };
    this.getUserInfoByAccessToken = function (wxAppId , accessToken , openId , onGet) {
        if( me.wxApps[wxAppId]){
            var data = {
                accessToken:accessToken,
                openId: openId
            };
            var urlFormt = me.urls.getUserInfo;
            var url = urlFormt;
            for( p in data){
                var k = "["+p+"]";
                var v = data[p];
                url = url.replace(k,v);
            }
            var res={
                status:-2,
                userInfo:null
            }
            request(url, function (err, responseUser, bodyUser) {
                if (responseUser && responseUser.statusCode == 200) {
                    var userInfo = JSON.parse(bodyUser);
                    if( userInfo.nickname && userInfo.nickname!=null && userInfo.nickname.length>0){
                        res.status =1 ;
                        res.userInfo = userInfo;
                    }
                }
                onGet(res);
            });
        }
    }
}

function THHKeyValue() {
    this.config={
        dataPath:"e:/app/kmsdev/dev/static/keyvalueData"
    };
    this.setData= function (key  , data) {
        var me = this;
        var res = false;
        try{
            var pathArr = key.split('/');
            pathArr.splice(pathArr.length-1,1)
            var dir = pathArr.join('/');
            dir = me.config.dataPath+"/"+dir;
            dir = dir.replace("//",'');
            var pathFlag = comm.makeDir(dir);
            if( fs.existsSync(dir) ){
                var fn = (me.config.dataPath+"/"+key).replace("//","/");
                if (fn.indexOf(".txt")<0){
                    fn = fn+".txt";
                }
                fs.writeFileSync(fn, data);
                res = true;
            }
        }
        catch (e) {
            console.log(e);
        }
        return res;
    }
    this.getData= function (key  , data) {
        var me = this;
        var res = "";
        try{
            var fn = (me.config.dataPath+"/"+key).replace("//","/");
            if (fn.indexOf(".txt")<0){
                fn = fn+".txt";
            }
            if( fs.existsSync(fn)){
                res = fs.readFileSync(fn,'utf-8');
            }
        }
        catch (e) {
            console.log(e);
        }
        return res;
    }
}

function THH() {
    var me = this;
    this.apiServer = new THHApi();
    this.kms = new THHKms();
    this.mq = new THHMQ();
    this.db = new THHDB();
    this.wx = new THHWx();
    this.wxLogin = new THHWxLogin();
    this.rooms = new THHAppRoom();
    this.hhKeyValue = new THHKeyValue();
}

/*
module.exports = {
    comm: comm,
    THhDB: THHDB,
    THHMQ: THHMQ,
    THHKms: THHKms,
    THHApi: THHApi,
    THH: THH
}
*/

var hh = new THH();
hh.db.apps.hhRa ={
    host:"tjiot.hhdata.cn" ,
    port:53306,
    uid:"root",
    pwd:"hhuc1115",
    db:"hhra" ,
    sqlPath:"E:/app/kmsdev/dev/svr/sqls"
};
hh.db.apps.hhRoom ={
    host:"tjiot.hhdata.cn" ,
    port:53306,
    uid:"root",
    pwd:"hhuc1115",
    db:"hhvideoroom" ,
    sqlPath:"E:/app/kmsdev/dev/svr/sqls"
};
hh.db.apps.hhVideoRoom ={
    host:"tjiot.hhdata.cn" ,
    port:53306,
    uid:"root",
    pwd:"hhuc1115",
    db:"hhvideoroom" ,
    sqlPath:"E:/app/kmsdev/dev/svr/sqls"
};

var routes ={
    "hello":function (result , request , response) {
        result.data ="hello";
        response.send(JSON.stringify(result));
    },
    dbQuery: function (result , request , response) {
        try{
            var appId = result.ps.appId ;
            var key = result.ps.key ;
            var ps  = JSON.parse(result.ps.ps) ;
            hh.db.queryByFn(appId , key , ps , function (err,res) {
                result.error = err;
                result.data = res;
                response.send(JSON.stringify(result));
            })
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    getServerTime: function (result , request , response) {
        try{
            result.data = ( new Date()).getTime();
            response.send(JSON.stringify(result));
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    kmsOpenChannel: function (result , request , response) {
        try{
            var channelId = result.ps.channelId ;
            var info = comm.extend({}, JSON.parse(result.ps.channelInfo));
            hh.rooms.openRoom(channelId , info, function (res) {
                if(res){
                    result.data = { id:res.roomId , kmsId:res.kmsId};
                }
                else{
                    result.error = "open channel faild.";
                }
                response.send(JSON.stringify(result));
            })
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    wxLogin: function (result , request , response) {
        try{
            var reqPs = {
                ak:"",
                code :"",
                openId:"" ,
                accessToken :"",
                accessTime:0,
                refreshToken:"",
                refreshTime:0,
                userInfo:{},
                loginUrl:""
            };
            hh.wx.requestUserInfo(result.ps , function (res) {
                result.data = res;
                response.send(JSON.stringify(result));
            })
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    kmsGetChannels: function (result , request , response) {
        try{
            hh.rooms.getRooms( function (res) {
                result.data =[];
                res.forEach(function (item) {
                    result.data.push({id:item.roomId , kmsId: item.kmsId , info:item.roomInfo});
                })
                response.send(JSON.stringify(result));
            })
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    kmsCloseChannel: function (result , request , response) {
        try{
            var channelId = result.ps.channelId ;
            hh.rooms.closeRoom( channelId,function (res) {
                result.data =res;
                response.send(JSON.stringify(result));
            })
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    kmsGetRoomInfo: function (result , request , response) {
        try{
            var channelId = result.ps.channelId ;
            hh.rooms.getRoomInfo( channelId,function (res) {
                result.data =res;
                response.send(JSON.stringify(result));
            })
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    kmsCreateEnd: function (result , request , response) {
        try{
    //roomId, endType, endId, endOptions, endInfo
            var roomId = result.ps.channelId ;
            var endId = result.ps.endId ;
            var endType = "WebRtcEndpoint" ;
            var endOptions = {} ;
            var info = comm.extend({}, JSON.parse(result.ps.endInfo));
            hh.rooms.createEnd( roomId,endType,endId,endOptions,info,function (res) {
                result.data =res;
                response.send(JSON.stringify(result));
            })
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    } ,
    
    /*   键值对操作   */
    setSvrData: function (result , request , response) {
        try{
            var key = result.ps.key ;
            var data = result.ps.data ;
            data = comm.isNull(data)?"":data;
            result.data = hh.hhKeyValue.setData(key , data);
            response.send(JSON.stringify(result));
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    } ,
    getSvrData: function (result , request , response) {
        try{
            var key = result.ps.key ;
            if( comm.isNull(key)){
                result.data ="";
            }
            else {
                result.data = hh.hhKeyValue.getData(key);
            }
            response.send(JSON.stringify(result));
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    } ,
    

    /* 微信登录服务 */
    hhWxLoginGetRedirectUrl:function (result , request , response){
        try{
            var wxAppId = result.ps.wxAppId;
            var state = result.ps.state;
            result.data = hh.wxLogin.getRedirectUrl(wxAppId, state);
            response.send(JSON.stringify(result));
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    hhWxLoginGetAccessTokenByCode:function (result , request , response){
        try{
            var wxAppId = result.ps.wxAppId;
            var code = result.ps.code;
            hh.wxLogin.getAccessTokenByCode(wxAppId, code , function (res) {
                result.data = res;
                response.send(JSON.stringify(result));
            });
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    hhWxLoginGetAccessTokenByRefresh:function (result , request , response){
        try{
            var wxAppId = result.ps.wxAppId;
            var refreshToken = result.ps.refreshToken;
            hh.wxLogin.getAccessTokenByRefresh(wxAppId, refreshToken , function (res) {
                result.data = res;
                response.send(JSON.stringify(result));
            });
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    },
    hhWxLoginGetUserInfoByAccessToken:function (result , request , response){
        try{
            var wxAppId = result.ps.wxAppId;
            var accessToken = result.ps.accessToken;
            var openId = result.ps.openId;
            hh.wxLogin.getUserInfoByAccessToken(wxAppId, accessToken, openId , function (res) {
                result.data = res;
                response.send(JSON.stringify(result));
            });
        }
        catch (e) {
            console.log(e);
            response.send(e.toString());
        }
    }
};
hh.apiServer.start(routes, function () {
    console.log('start web api');
})
